/*
 * JNIWrapper.cpp  0.4.0 / Nov 14, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "JNIWrapper.h"

// JNIWrapper :: Public Static Member Functions.  ------------------------------

/*!
 * \brief Checks for JNI exceptions.
 *
 * \param env the JNIEnv pointer
 */
void JNIWrapper::checkException(JNIEnv *env)
{
  Q_ASSERT(env);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
}

/*!
 * \brief Test if an exception has occurred.
 *
 * \param env the JNIEnv pointer
 *
 * \return \c true if the exception has occurred
 */
bool JNIWrapper::testException(JNIEnv *env)
{
  Q_ASSERT(env);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return true;
  }
  return false;
}

/*!
 * \brief Prints the error message and terminates virtual machine.
 *        <p>
 *          NOTE: This method does not return.
 *        </p>
 *
 * \param env the JNIEnv pointer
 * \param errorMessage the error message
 */
void JNIWrapper::fatalError(JNIEnv *env, const char *errorMessage)
{
  Q_ASSERT(env);
  env->FatalError(errorMessage);  // does not return
}

/*!
 * \brief Throws java's internal error.
 *
 * \param env the JNIEnv pointer
 * \param errorMessage the error message
 */
void JNIWrapper::throwInternalError(JNIEnv *env, const char *errorMessage)
{
  Q_ASSERT(env);
  jclass cls = env->FindClass("java/lang/InternalError");
  if (cls) {
    env->ThrowNew(cls, errorMessage);
    env->DeleteLocalRef(cls);
  }
}

/*!
 * \brief Throws java's out of memory error.
 *
 * \param env the JNIEnv pointer
 * \param errorMessage the error message
 */
void JNIWrapper::throwOutOfMemoryError(JNIEnv *env, const char *errorMessage)
{
  Q_ASSERT(env);
  jclass cls = env->FindClass("java/lang/OutOfMemoryError");
  if (cls) {
    env->ThrowNew(cls, errorMessage);
    env->DeleteLocalRef(cls);
  }
}

/*!
 * \brief Throws java's runtime exception.
 *
 * \param env the JNIEnv pointer
 * \param exceptionMessage the exception message
 */
void JNIWrapper::throwRuntimeExcpetion(JNIEnv *env,
                                       const char *exceptionMessage)
{
  Q_ASSERT(env);
  jclass cls = env->FindClass("java/lang/RuntimeException");
  if (cls) {
    env->ThrowNew(cls, exceptionMessage);
    env->DeleteLocalRef(cls);
  }
}

/*!
 * \brief Returns the fieldID for an instance field of a class.
 *
 * \param env the JNIEnv pointer
 * \param cls the class
 * \param name the field name
 * \param sig the field signature
 *
 * \return the fieldID for an instance field of a class
 */
jfieldID JNIWrapper::getFieldID(JNIEnv *env, jclass cls, const char *name,
                                const char *sig)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(name);
  Q_ASSERT(sig);
  jfieldID fid = env->GetFieldID(cls, name, sig);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return fid;
}

/*!
 * \brief Returns the field ID for a static field of a class or interface.
 *
 * \param env the JNIEnv pointer
 * \param cls the class
 * \param name the field name
 * \param sig the field signature
 *
 * \return the field ID for a static field of a class or interface
 */
jfieldID JNIWrapper::getStaticFieldID(JNIEnv *env, jclass cls,
                                      const char *name, const char *sig)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(name);
  Q_ASSERT(sig);
  jfieldID fid = env->GetStaticFieldID(cls, name, sig);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return fid;
}

/*!
 * \brief Returns the methodID for an instance method of a class or interface.
 *
 * \param env the JNIEnv pointer
 * \param cls the class
 * \param name the method name
 * \param sig the method signature
 *
 * \return the methodID for an instance method of a class or interface
 */
jmethodID JNIWrapper::getMethodID(JNIEnv *env, jclass cls, const char *name,
                                  const char *sig)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(name);
  Q_ASSERT(sig);
  jmethodID mid = env->GetMethodID(cls, name, sig);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return mid;
}

/*!
 * \brief Returns the method ID for a static method of a class.
 *
 * \param env the JNIEnv pointer
 * \param cls the class
 * \param name the method name
 * \param sig the method signature
 *
 * \return the method ID for a static method of a class
 */
jmethodID JNIWrapper::getStaticMethodID(JNIEnv *env, jclass cls,
                                        const char *name, const char *sig)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(name);
  Q_ASSERT(sig);
  jmethodID mid = env->GetStaticMethodID(cls, name, sig);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return mid;
}

/*!
 * \brief Returns the value of the object field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the object field of the specified object
 */
jobject JNIWrapper::getObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetObjectField(obj, fieldID);
}

/*!
 * \brief Sets the value of the object field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setObjectField(JNIEnv *env, jobject obj, jfieldID fieldID,
                                jobject val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetObjectField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the boolean field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the boolean field of the specified object
 */
jboolean JNIWrapper::getBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetBooleanField(obj, fieldID);
}

/*!
 * \brief Sets the value of the boolean field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID,
                                 jboolean val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetIntField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the byte field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the byte field of the specified object
 */
jbyte JNIWrapper::getByteField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetByteField(obj, fieldID);
}

/*!
 * \brief Sets the value of the byte field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setByteField(JNIEnv *env, jobject obj, jfieldID fieldID,
                              jbyte val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetByteField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the char field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the char field of the specified object
 */
jchar JNIWrapper::getCharField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetCharField(obj, fieldID);
}

/*!
 * \brief Sets the value of the char field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setCharField(JNIEnv *env, jobject obj, jfieldID fieldID,
                              jchar val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetCharField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the short field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the short field of the specified object
 */
jshort JNIWrapper::getShortField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetShortField(obj, fieldID);
}

/*!
 * \brief Sets the value of the short field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setShortField(JNIEnv *env, jobject obj, jfieldID fieldID,
                               jshort val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetShortField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the int field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the int field of the specified object
 */
jint JNIWrapper::getIntField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetIntField(obj, fieldID);
}

/*!
 * \brief Sets the value of the int field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setIntField(JNIEnv *env, jobject obj, jfieldID fieldID,
                             jint val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetIntField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the long field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the long field of the specified object
 */
jlong JNIWrapper::getLongField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetLongField(obj, fieldID);
}

/*!
 * \brief Sets the value of the long field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setLongField(JNIEnv *env, jobject obj, jfieldID fieldID,
                              jlong val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetLongField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the float field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the float field of the specified object
 */
jfloat JNIWrapper::getFloatField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetFloatField(obj, fieldID);
}

/*!
 * \brief Sets the value of the float field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setFloatField(JNIEnv *env, jobject obj, jfieldID fieldID,
                               jfloat val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetFloatField(obj, fieldID, val);
}

/*!
 * \brief Returns the value of the double field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 *
 * \return the value of the double field of the specified object
 */
jdouble JNIWrapper::getDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  return env->GetDoubleField(obj, fieldID);
}

/*!
 * \brief Sets the value of the double field of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 * \param fieldID the field ID
 * \param val the new value
 */
void JNIWrapper::setDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID,
                                jdouble val)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(fieldID);
  env->SetDoubleField(obj, fieldID, val);
}

/*!
 * \brief Calls JNI object method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callObjectMethod(JNIEnv *env, jobject &result, jobject obj,
                                  jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  result = env->CallObjectMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI object method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callObjectMethod(JNIEnv *env, jobject &result, jobject obj,
                                  jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallObjectMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI boolean method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callBooleanMethod(JNIEnv *env, jboolean &result, jobject obj,
                                   jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallBooleanMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI boolean method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callBooleanMethod(JNIEnv *env, jboolean &result,
                                   jobject obj, jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallBooleanMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI byte method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callByteMethod(JNIEnv *env, jbyte &result, jobject obj,
                                jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallByteMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI byte method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callByteMethod(JNIEnv *env, jbyte &result, jobject obj,
                                jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallByteMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI char method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callCharMethod(JNIEnv *env, jchar &result, jobject obj,
                                jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallCharMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI char method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callCharMethod(JNIEnv *env, jchar &result, jobject obj,
                                jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallCharMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI short method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callShortMethod(JNIEnv *env, jshort &result, jobject obj,
                                 jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallShortMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI short method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callShortMethod(JNIEnv *env, jshort &result, jobject obj,
                                 jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallShortMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI int method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callIntMethod(JNIEnv *env, jint &result, jobject obj,
                               jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallIntMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI int method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callIntMethod(JNIEnv *env, jint &result, jobject obj,
                               jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallIntMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI long method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callLongMethod(JNIEnv *env, jlong &result, jobject obj,
                                jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallLongMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI long method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callLongMethod(JNIEnv *env, jlong &result, jobject obj,
                                jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallLongMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI float method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callFloatMethod(JNIEnv *env, jfloat&result, jobject obj,
                                 jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallFloatMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI float method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callFloatMethod(JNIEnv *env, jfloat &result, jobject obj,
                                 jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallFloatMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI double method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callDoubleMethod(JNIEnv *env, jdouble &result, jobject obj,
                                  jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallDoubleMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI double method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param obj the jobject
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callDoubleMethod(JNIEnv *env, jdouble &result, jobject obj,
                                  jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallDoubleMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI void method.
 *
 * \param env the JNIEnv pointer
 * \param obj the java object
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID,
                                va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  env->CallVoidMethodV(obj, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI void method.
 *
 * \param env the JNIEnv pointer
 * \param obj the java object
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID,
                                ...)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  env->CallVoidMethodV(obj, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Returns jstring representation of the specified object.
 *
 * \param env the JNIEnv pointer
 * \param obj the object
 *
 * \return jstring representation of the specified object
 */
jstring JNIWrapper::toString(JNIEnv *env, jobject obj)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  jstring str = (jstring)env->CallObjectMethod(obj, sm_toStringMID);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return str;
}

/*!
 * \brief Creates new Java string.
 *
 * \param env the JNIEnv pointer
 * \param uchars the unicode char array
 * \param len the length of the char array
 *
 * \return new Java string object
 */
jstring JNIWrapper::newString(JNIEnv *env, const jchar *uchars, jsize len)
{
  Q_ASSERT(env);
  Q_ASSERT(uchars);
  Q_ASSERT(len >= 0);
  jstring str = env->NewString(uchars, len);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return str;
}

/*!
 * \brief Creates new Java string.
 *
 * \param env the JNIEnv pointer
 * \param bytes the UTF-8 char array
 *
 * \return new Java string object
 */
jstring JNIWrapper::newStringUTF(JNIEnv *env, const char *bytes)
{
  Q_ASSERT(env);
  Q_ASSERT(bytes);
  jstring str = env->NewStringUTF(bytes);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return str;
}

/*!
 * \brief Calls JNI static void method.
 *
 * \param env the JNIEnv pointer
 * \param cls the java class
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callStaticVoidMethod(JNIEnv *env, jclass cls,
                                      jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  env->CallStaticVoidMethodV(cls, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI static void method.
 *
 * \param env the JNIEnv pointer
 * \param cls the java class
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callStaticVoidMethod(JNIEnv *env, jclass cls,
                                      jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  env->CallStaticVoidMethodV(cls, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI static int method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param cls the java class
 * \param methodID the method ID
 * \param args the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callStaticIntMethod(JNIEnv *env, jint &result, jclass cls,
                                     jmethodID methodID, va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(methodID);
  Q_ASSERT(args);
  result = env->CallStaticIntMethodV(cls, methodID, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Calls JNI static void method.
 *
 * \param env the JNIEnv pointer
 * \param result the result
 * \param cls the java class
 * \param methodID the method ID
 * \param ... the method arguments
 *
 * \return \c true if no exception is thrown
 */
bool JNIWrapper::callStaticIntMethod(JNIEnv *env, jint &result, jclass cls,
                                     jmethodID methodID, ...)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(methodID);
  va_list args;
  va_start(args, methodID);
  result = env->CallStaticIntMethodV(cls, methodID, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    return false;
  }
  return true;
}

/*!
 * \brief Creates and constructs new Java object.
 *
 * \param env the JNIEnv pointer
 * \param cls the object class
 * \param constructor the class constructor
 * \param args the constructor arguments
 *
 * \return new Java object
 */
jobject JNIWrapper::newObject(JNIEnv *env, jclass cls, jmethodID constructor,
                              va_list &args)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(constructor);
  Q_ASSERT(args);
  jobject obj = env->NewObjectV(cls, constructor, args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return obj;
}

/*!
 * \brief Creates and constructs new Java object.
 *
 * \param env the JNIEnv pointer
 * \param cls the object class
 * \param constructor the class constructor
 * \param ... the constructor arguments
 *
 * \return new Java object
 */
jobject JNIWrapper::newObject(JNIEnv *env, jclass cls, jmethodID constructor,
                              ...)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(constructor);
  va_list args;
  va_start(args, constructor);
  jobject obj = env->NewObjectV(cls, constructor, args);
  va_end(args);
  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return obj;
}

/*!
 * \brief Creates new java object array.
 *
 * \param env the JNIEnv pointer
 * \param cls the class of the array elements
 * \param len the length of the array
 *
 * \return the java object array
 */
jobjectArray JNIWrapper::newObjectArray(JNIEnv *env, jclass cls, jsize len)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(len >= 0);
  jobjectArray objarr = env->NewObjectArray(len, cls, 0);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return objarr;
}

/*!
 * \brief Creates new java string array.
 *
 * \param env the JNIEnv pointer
 * \param len the length of the array
 *
 * \return the java string array
 */
jobjectArray JNIWrapper::newStringArray(JNIEnv *env, jsize len)
{
  Q_ASSERT(env);
  Q_ASSERT(len >= 0);
  jobjectArray stringArray = env->NewObjectArray(len, sm_stringClass, 0);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return stringArray;
}

/*!
 * \brief Creates new java byte array.
 *
 * \param env the JNIEnv pointer
 * \param len the length of the array
 *
 * \return the java byte array
 */
jbyteArray JNIWrapper::newByteArray(JNIEnv *env, jsize len)
{
  Q_ASSERT(env);
  Q_ASSERT(len >= 0);
  jbyteArray byteArray = env->NewByteArray(len);
  if (env->ExceptionCheck()) { // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return byteArray;
}

/*!
 * \brief Returns new Java global reference to the specified Java object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Java object
 *
 * \return new Java global reference to the specified Java object
 */
jobject JNIWrapper::newGlobalRef(JNIEnv *env, jobject obj)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  jobject objref = env->NewGlobalRef(obj);
  if (env->ExceptionCheck()) { // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return objref;
}

/*!
 * \brief Returns new Java weak reference to the specified Java object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Java object
 *
 * \return new Java weak reference to the specified Java object
 */
jweak JNIWrapper::newWeakGlobalRef(JNIEnv *env, jobject obj)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  jweak wobjref = env->NewWeakGlobalRef(obj);
  if (env->ExceptionCheck()) {  // checks for OutOfMemoryError
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  return wobjref;
}

/*!
 * \brief Deletes the Java reference.
 *
 * \param env the JNIEnv pointer
 * \param objref the Java reference
 */
void JNIWrapper::deleteGlobalRef(JNIEnv *env, jobject &objref)
{
  Q_ASSERT(env);
  Q_ASSERT(objref);
  env->DeleteGlobalRef(objref);
  objref = 0;
}

/*!
 * \brief Deletes the Java weak reference.
 *
 * \param env the JNIEnv pointer
 * \param wobjref the Java weak reference
 */
void JNIWrapper::deleteWeakGlobalRef(JNIEnv *env, jweak &wobjref)
{
  Q_ASSERT(env);
  Q_ASSERT(wobjref);
  env->DeleteWeakGlobalRef(wobjref);
  wobjref = 0;
}

/*!
 * \brief Returns \c true if the specified weak reference is alive.
 *
 * \param env the JNIEnv pointer
 * \param wobjref the Java weak reference
 *
 * \return \c true if the specified weak reference is alive
 */
bool JNIWrapper::isLiveRef(JNIEnv *env, jweak wobjref)
{
  Q_ASSERT(env);
  Q_ASSERT(wobjref);
  return (!(env->IsSameObject(wobjref, 0)));
}

// JNIWrapper :: Private Static Member Function. -------------------------------

void JNIWrapper::initialize(JNIEnv *env)
{
  Q_ASSERT(env);
  Q_ASSERT(!sm_toStringMID);
  sm_objectClass = env->FindClass("java/lang/Object");
  sm_stringClass = env->FindClass("java/lang/String");
  if (!sm_objectClass || !sm_stringClass) {
    env->FatalError("JNIWrapper initialization failed");  // does not return
  }
  sm_objectClass = (jclass)env->NewGlobalRef(sm_objectClass);
  sm_stringClass = (jclass)env->NewGlobalRef(sm_stringClass);
  if (!sm_objectClass || !sm_stringClass) {
    env->FatalError("JNIWrapper initialization failed");  // does not return
  }
  sm_toStringMID = env->GetMethodID(sm_objectClass, "toString",
                                    "()Ljava/lang/String;");
  if (!sm_toStringMID) {
    env->FatalError("JNIWrapper initialization failed");  // does not return
  }
}

// JNIWrapper :: Private Static Data Member. -----------------------------------

jclass JNIWrapper::sm_objectClass = 0;
jclass JNIWrapper::sm_stringClass = 0;
jmethodID JNIWrapper::sm_toStringMID = 0;

